/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.newupbank.xmlparser;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructField;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
// import com.newupbank.bgc.basic.util.json.BasicJsonUtil;


import jodd.util.StringUtil;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;

/**
 * 0.0.3 空行处理 使用方法： select MulXmlParser1( 字段/xml内容 , "父节点", "节点1", "节点2", "节点2"
 * ) from table ; 只解析多行节点，如果不存在则为空 ， 多行的只能使用一个父节点
 *
 * @author lifanhong
 *
 */
public class XmlParser_bak extends GenericUDTF {

	// public static final BasicJsonUtil BJU = BasicJsonUtil.getInstance();

	@Override
	public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
		List<?> inputFields = argOIs.getAllStructFieldRefs();
		List<String> fieldName = new ArrayList<>();
		List<ObjectInspector> resType = new ArrayList<>();

		for (int j = 0; j < (inputFields.size() - 1); j++) {
			// StructField sf = (StructField) inputFields.get(j);
			fieldName.add("c" + j);
			resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
		}
		// 返回分别为列名 和 列类型
		return ObjectInspectorFactory.getStandardStructObjectInspector(fieldName, resType);
	}

	@Override
	public void process(Object[] objects) throws HiveException {
		if (objects.length < 2) {
			forward(objects);
			return;
		}
		String strXml = null;
		Document document = null;
		SAXReader reader = null;
		StringReader stringReader = null;
		List<XmlParserConfig> configList = null;
		Map<String, String> one2nMap = null;
		String fatherNode = null;
		List<Node> nodeList = null;
		try {
			// 初始化
			strXml = Objects.toString(objects[0]);
			if (StringUtil.isEmpty(strXml)) {
				return;
			}
			reader = new SAXReader();
			stringReader = new StringReader(strXml);
			document = reader.read(stringReader);
			// 转为javabean
			configList = toConfigList(objects);
			// 先1:N的单个字段
			one2nMap = getSingleNodeText(configList, document);
			// 获取公共节点
			fatherNode = getCommonNode(configList);
			// 如果有公共节点
			if (!StringUtils.isEmpty(fatherNode)) {
				// 先获取公共节点,然后生成
				nodeList = document.selectNodes(fatherNode);
				int row = 1;
				if (nodeList != null && !nodeList.isEmpty()) {
					for (Node node : nodeList) {
						// 生成数据数组
						List<String[]> data = geneRow(configList, one2nMap, fatherNode, node, row);
						for (String[] arrStr : data) {
							JudgingEmpty(arrStr);
							 System.out.println(Arrays.toString(arrStr));

						}

						row++;
					}
				} else {
					String[] data = geneRow(configList, one2nMap, fatherNode);
					 JudgingEmpty(data);
					 forward(data);
				}
			} else if (!one2nMap.isEmpty()) {
				String[] data = geneRow(configList, one2nMap, fatherNode);
				 JudgingEmpty(data);
				 forward(data);
			}
		} catch (Exception ex) {
			System.err.println("configList=" + configList);
			System.err.println("one2nMap=" + one2nMap);
			System.err.println("fatherNode=" + fatherNode);
			System.err.println("nodeList=" + nodeList);
			ex.printStackTrace();
			throw new HiveException(ex);
		} finally {
			if (stringReader != null) {
				stringReader.close();
				stringReader = null;
			}
			document = null;
			reader = null;
		}
	}

	public List<String[]> geneRow(List<XmlParserConfig> configList, Map<String, String> one2nMap, String fatherNode,
			Node node, int rowNum) throws Exception {
		Object[] ret = new Object[configList.size()];
		List<List<String>> list0 = new ArrayList<>();
		// list0.add()
		// ArrayList<Object[]> resultList = new ArrayList<Object[]>();
		String xs = null;
		String nodes = null;
		try {
			for (int i = 0; i < configList.size(); i++) {
				XmlParserConfig xpc = configList.get(i);
				if (XmlParserConfig.Type1N.equals(xpc.getType())) {
					ret[i] = one2nMap.get(xpc.getTag());
				} else if (XmlParserConfig.TypeRowNum.equals(xpc.getType())) {
					ret[i] = rowNum + "";
				} else if (XmlParserConfig.TypeN.equals(xpc.getType())) {
					nodes = xpc.getSrc();
					if (nodes.length() <= fatherNode.length()) {
						xs = nodes;
					} else {
						xs = nodes.substring(fatherNode.length() + 1);
					}
					if (StringUtils.isEmpty(xs)) {
						ret[i] = "";
						continue;
					}

					List<Node> nmList = node.selectNodes(xs);
					if (nmList != null && !nmList.isEmpty()) {
						List<String> nmtList = new ArrayList<>(nmList.size());
						for (Node nm : nmList) {
							if (nm != null) {
//								System.out.println(nm.getText());
								nmtList.add(nm.getText());
								continue;
							} else {
								ret[i] = "";
								continue;
							}
						}
						ret[i] = nmtList;
					} else {
						ret[i] = "";
						continue;
					}
				}else if (XmlParserConfig.TypeNN.equals(xpc.getType())) {//多对多
					nodes = xpc.getSrc();
					System.out.println(nodes);
				}
				else {
					throw new Exception(" not super type " + xpc.getType());
				}
			}
		} catch (Exception ex) {
			System.err.println("nodes=" + nodes);
			System.err.println("xs=" + xs);
			ex.printStackTrace();
			throw ex;
		}
		List<String[]> retss = parseMO(ret);
//		System.out.println(ret);

		return retss;
	}

	public List<String[]> parseMO(Object[] ret) {
		// 2.把TempPojo放入队列
		Queue<TempPojo> queue = new LinkedList<TempPojo>();
		TempPojo tempPojo = new TempPojo();
		tempPojo.setStep(0);
		tempPojo.setPojoArr(ret);
		queue.add(tempPojo);

		// 存放结果的集合
		List<String[]> resultList = new ArrayList<>();

		// 3.遍历队列
		while (queue.size() > 0) {
			TempPojo tempPojo1 = queue.poll();

			int step = tempPojo1.getStep();
			Object[] pojoArr = tempPojo1.getPojoArr();

			// 3.1步长与初始集合长度相同，已经拆解到最后一个集合.拆解后将结果放入resultList
			if (step == pojoArr.length - 1) {

				List<String> tempList1 = (List<String>) pojoArr[step];// 拿到最后一个集合
				for (String str1 : tempList1) {
					// 拆解最后一个集合并放入结果集合【男，1，a】
					String[] arrStr = new String[pojoArr.length];
					for (int i = 0; i < pojoArr.length; i++) {
						if (i == step) {
							arrStr[i] = str1;
						} else {
							arrStr[i] = (String) pojoArr[i];
						}
					}

					resultList.add(arrStr);
				}

			}

			// 3.2如果步长小于初始集合长度，拆解后，构建pojo并加入队列.
			if (step < pojoArr.length - 1) {
				List<String> tempList1 = (List<String>) pojoArr[step];// 拿到step对应要拆解的集合
				for (String str1 : tempList1) {
					TempPojo tempPojo2 = new TempPojo();

					Object[] objArr = new Object[pojoArr.length];
					for (int i = 0; i < pojoArr.length; i++) {
						if (i == step) {
							objArr[i] = str1;
						} else {
							objArr[i] = pojoArr[i];
						}
					}
					tempPojo2.setStep((step + 1));
					tempPojo2.setPojoArr(objArr);
					queue.add(tempPojo2);
				}

			}

		}

		// 4.打印结果
		for (String[] arrStr : resultList) {

			// for (String s : arrStr) {
			// System.out.print(s + "\t");
			// }
//			System.out.println(Arrays.toString(arrStr));

		}
		return resultList;
	}

	public String[] geneRow(List<XmlParserConfig> configList, Map<String, String> one2nMap, String fatherNode)
			throws Exception {
		String[] ret = new String[configList.size()];
		for (int i = 0; i < configList.size(); i++) {
			XmlParserConfig xpc = configList.get(i);
			if (XmlParserConfig.Type1N.equals(xpc.getType())) {
				ret[i] = one2nMap.get(xpc.getTag());
			} else if (XmlParserConfig.TypeRowNum.equals(xpc.getType())) {
				ret[i] = "1";
			} else if (XmlParserConfig.TypeN.equals(xpc.getType())) {
				ret[i] = "";
				continue;
			} else {
				throw new Exception(" not super type " + xpc.getType());
			}
		}
		return ret;
	}

	public String getCommonNode(List<XmlParserConfig> configList) throws Exception {
		// TODO Auto-generated method stub
		String ret = "";
		// StringUtils.getCommonPrefix(strs);
		List<String> nList = new ArrayList<>(configList.size());
		for (int i = 0; i < configList.size(); i++) {
			XmlParserConfig xpc = configList.get(i);
			if (XmlParserConfig.TypeN.equals(xpc.getType())) {
				nList.add(xpc.getSrc());
			}else if (XmlParserConfig.TypeNN.equals(xpc.getType())) {
				nList.add(xpc.getSrc());
			}
		}
		if (nList.isEmpty()) {
			return ret;
		}
		// 获取前置内容
		String[] sts = new String[nList.size()];
		sts = nList.toArray(sts);
		ret = StringUtils.getCommonPrefix(sts);
		if (StringUtils.isEmpty(ret) || "/".equals(ret)) {
			throw new Exception(" not have  the common node ");
		}
		if (ret.endsWith("@")) {
			ret = ret.substring(0, ret.length() - 1);
		}
		if (ret.endsWith("/")) {
			ret = ret.substring(0, ret.length() - 1);
		}
		return ret;
	}

	private List<XmlParserConfig> toConfigList(Object[] objects) throws IOException {
		// TODO Auto-generated method stub
		List<XmlParserConfig> configList = new ArrayList<>(objects.length - 1);
		for (int i = 1; i < objects.length; i++) {
			String tmps = Objects.toString(objects[i]);
			// XmlParserConfig xpc = BJU.toJavaBean(tmps, XmlParserConfig.class);
			XmlParserConfig xpc = JSON.parseObject(tmps,XmlParserConfig.class);
			configList.add(xpc);
		}
		return configList;
	}

	private Map<String, String> getSingleNodeText(List<XmlParserConfig> configList, Document document) {
		// TODO Auto-generated method stub
		Map<String, String> one2nMap = new HashMap<>(configList.size());
		for (XmlParserConfig xpc : configList) {
			if (XmlParserConfig.Type1N.equals(xpc.getType())) {
				Node node = document.selectSingleNode(xpc.getSrc());
				if (node != null) {
					one2nMap.put(xpc.getTag(), node.getText());
				}
			}
		}
		return one2nMap;
	}

	public void processOld(Object[] objects) throws HiveException {
		List<Element> nodeList = new ArrayList<>();
		List<String> valueList = new ArrayList();
		List<Element> node2List = new ArrayList<>();
		List<String> value2List = new ArrayList();
		List<Element> fileLength = new ArrayList();
		List<String> arrayList = new ArrayList();
		List<String[]> resultList = new ArrayList();
		List<String> valueSize = new ArrayList();

		String strXml = Objects.toString(objects[0]);
		Document document = null;
		SAXReader reader = new SAXReader();
		StringReader stringReader = new StringReader(strXml);
		try {
			document = reader.read(stringReader);

		} catch (DocumentException e) {
			e.printStackTrace();
			throw new HiveException(e);
		}
		if (document != null) {
			nodeList = document.selectNodes(objects[1].toString());
			for (Element element : nodeList) {
				valueList.add(element.getText());
			}
			fileLength = document.selectNodes(objects[2].toString());
			int lineNum = 0;
			if (fileLength.size() > 0) {
				for (Element element : fileLength) {
					valueSize.add(element.getText());
				}
				lineNum = valueSize.size();
			}
			for (int k = 0; k < lineNum; k++) {
				arrayList.clear();
				arrayList.add(valueList.get(0));
				for (int i = 2; i < objects.length - 1; i++) {
					node2List.clear();
					value2List.clear();
					node2List = document.selectNodes(objects[i].toString());
					if (node2List.size() > 0) {
						for (Element element : node2List) {
							value2List.add(element.getText());
						}
						arrayList.add(value2List.get(k));
					}
				}
				arrayList.add((k + 1) + "");
				String[] array = arrayList.toArray(new String[arrayList.size()]);
				resultList.add(array);
				forward(resultList.get(0));
				resultList.clear();
			}

		}

	}

	@Override
	public void close() throws HiveException {

	}

	// 判断(除AppId外)字段值是否全为空，全为空则不返回数据
	public void JudgingEmpty(String[] data) throws HiveException {
		int b = 0;
		for (int i = 1; i < data.length; i++) {
			if (data[i].length() > 0) {
				b = b + 1;
			} else {
				continue;
			}
		}
		if (b > 0) {
//			System.out.println("b>0  " + b);
//			 forward(data);
		} else {
			System.out.println("不返回数据");
			return;
		}
	}

	public static void main(String[] args) {
		XmlParser_bak xmlp = new XmlParser_bak();
		String xml = "<Application AppId=\"jksidhaish8796987sadfasdfjd100842\" SourceCode=\"newupBank\">"
				+ "<ScoreModelReturnInfo FinalScore=\"462.0\" ScoreModelName=\"申请评分模型1\">		"
				+ "<ScoredCharacteristic BaselineScore=\"0.2\" BinLabel=\"男1\" />	<ScoredCharacteristic "
				+ "BaselineScore=\"0.0\" BinLabel=\"男\" />		"
				+ "</ScoreModelReturnInfo>	<ReturnInfoVariable workingYears=\"30.0\"/>	"
				+ "<ScoreModelReturnInfo FinalScore=\"461.0\" ScoreModelName=\"申请评分模型\">		"
				+ "<ScoredCharacteristic BaselineScore=\"0.1\" BinLabel=\"女\" /></ScoreModelReturnInfo>"
				+ "+<ScoreModelReturnInfo FinalScore=\"451.0\" ScoreModelName=\"申请评分模型5\">		"
				+ "<ScoredCharacteristic BaselineScore=\"0.5\" BinLabel=\"女5\" /></ScoreModelReturnInfo>"
				+ "</Application>";
		System.out.println(xml);
		String arr = "{\"src\":\"/Application/ScoreModelReturnInfo/ScoredCharacteristic/@BinLabel\",\"tag\":\"c1\",\"type\":\"NN\"}";
		String arr1 = "{\"src\":\"/Application/ScoreModelReturnInfo/@ScoreModelName\",\"tag\":\"c1\",\"type\":\"NN\"}";
//		String arr2 = "{\"src\":\"/Application/@AppId\",\"tag\":\"c1\",\"type\":\"N\"}";
		// String arr1 =
		// "{\"src\":\"/Application/ScoreModelReturnInfo/@FinalScore\",\"tag\":\"c1\",\"type\":\"N\"}";
		// String tablename = "ScoreModelReturnInfo";
		Object[] obj = new Object[3];
		// System.out.println(arr.toString());
		obj[0] = xml;
		obj[1] = arr;
		obj[2] = arr1;
//		obj[3] = arr2;
		try {
			xmlp.process(obj);
		} catch (HiveException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
